home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr22 / byte24.zip / BENCHSUB.ASM < prev    next >
Assembly Source File  |  1993-04-14  |  52KB  |  2,608 lines

  1. ; «PL1»
  2. ;
  3. ; Assembly routines for BYTE benchmarks
  4. ; This is the heart of all of the routines.
  5. ;
  6. ;
  7. ; NOTE: Version 2.4 changes made 4/14/93 by R.G.
  8. ; All low-level routines now execute multiple times
  9. ; per iteration.  These counts MUST be kept in sync with the
  10. ; constants set in the C code (BENCHCOD.C).
  11.  
  12. ;General equates
  13. TRUE        equ    1
  14. FALSE        equ    0
  15.  
  16. ;Equates for timer routine
  17. BIOS_TIME_LO    equ    006ch
  18. BIOS_DATASEG    equ    0040h
  19. TIMER_MODE    equ    43h
  20. TIMER0        equ    40h
  21. MAX_COUNT    equ    0ffffh
  22.  
  23. DOSSEG
  24. .MODEL    small
  25. FDATA    SEGMENT DWORD PUBLIC
  26. FAC1    DQ    3.0E0
  27. FAC2    DQ      2.0E0
  28. FAC3    DQ    5.050E0
  29. FAC4    DQ    5.050E0
  30. FRESULT    DQ    ?
  31. FDATA    ENDS
  32.  
  33. .DATA
  34.  
  35. ;Definitions for high-resolution timer.
  36. count_low    dw    0    ;number of interrupt tics
  37. count_micro    dw    0    ;calc. from interrrupt tics
  38. count_milli    dw    0    ;calc. from interrrupt tics
  39. timer_micro    dw    0    ;final value
  40. timer_milli    dw    0    ;  "
  41. timer_sec    dw    0    ;  "
  42. svd_8253_count    dw    0    ;storage space
  43. timer_convert    dw    8381    ;838.096 nsec per tick
  44. count_convert    dw    54926    ;54.925 mill-sec per count
  45. ten_thousand    dw    10000
  46. five_thousand    dw    5000
  47. thousand    dw    1000
  48.  
  49. extrn        _timeradjust:word    ;timer adjustment value
  50. extrn        _machine_config: BYTE
  51. coproc        equ    word ptr _machine_config+6
  52.  
  53. ;Definitions for floating-point
  54. INDEFINITE DD    0FFC00000R    ;Indefinite value
  55. IOMEGA    DQ    ?        ;Holds value of i omega
  56. FSTATUS    DW    ?        ;Holds status field
  57. STARTX    DQ    ?        ;For trapezoid
  58. MINUS2    DD    -2.0        ;Guess
  59. PIDIV2    DT    1.5707963267948966192 ;pi/2
  60.  
  61. ;Definitions for 8087
  62. CW_87 RECORD RES871:3,INF:1,RND:2,PRECC:2,ERRE:1,RES872:1,PRECM:1,UNFM:1,OVFM:1,ZDM:1,DNM:1,INVM:1
  63.  
  64. SW_87    RECORD    BUSY:1,COND3:1,TOP:3,COND2:1,COND1:1,COND0:1,ERRP:1,RES873:1,PRCE:1,UNFE:1,OVFE:1,ZDE:1,DNE:1,INVE:1
  65.  
  66. ;Definitions for EMS routines
  67. HANDLE1        DW    ?    ;Storage for first handle
  68. HANDLE2        DW    ?    ;Storage for second handle
  69.  
  70. ;Configuration stuff for Hercules mode
  71. CRTCP    DB    00H,35H        ;54 chars horizontal
  72.     DB    01,2DH        ;45 displayed
  73.     DB    02,2EH        ;Sync at 46th char
  74.     DB    03,07H        ;Sync width 7 char clocks
  75.     DB    4,5BH        ;Vert total of 92 characters
  76.     DB    05,02H        ;Vert adjust of 2 scan lines
  77.     DB    06,57H        ;Vert displayed of 87 char rows
  78.     DB    07,57H        ;Vert. sync after 87th char row
  79.     DB    09,03H        ;Max scan line, 4 scan lines per char
  80. BDATA    DB    7        ;CRT_MODE
  81.     DW    80        ;CRT_COLS
  82.     DW    8000H        ;CRT_LEN
  83.     DW    0        ;CRT_START
  84.     DW    8 DUP (0)    ;CURSOR_POSN
  85.     DW    0        ;CURSOR_MODE
  86.     DB    0        ;ACTIVE_PAGE
  87.     DW    3B4H        ;ADDR_6845
  88. CRTMD    DB    0AH        ;CRT_MODE_SET
  89.     DB    0        ;PALLETTE
  90. BDLEN    EQU    $-BDATA
  91.  
  92. .CODE
  93.  
  94.  
  95. ;****************************
  96. ;       do_sieve            *
  97. ;****************************
  98. ; This routine is called from C with the following
  99. ;       int do_sieve(flagseg,size);
  100. ; flagseg is the segment holding the flags array
  101. ; size  is the size of the flags array
  102. ; The routine returns the number of primes found
  103. ; 4/14/93 !! This version executes 25 sieves per iteration.--RG
  104.     PUBLIC    _do_sieve
  105. FLAGSEG        equ    [BP+4]
  106. SSIZE        equ    [BP+6]
  107.  
  108. _do_sieve    PROC    NEAR
  109. ;Save registers
  110.         PUSH    BP
  111.         MOV    BP,SP
  112.         PUSH    BX
  113.         PUSH    CX
  114.         PUSH    DX
  115.         PUSH    SI
  116.         PUSH    DI
  117.         PUSH    DS
  118.         PUSH    ES
  119. ;Set loop count -- 4/14/93 RG
  120.         MOV    CX,25
  121. ;Clear count
  122. DS0:
  123.         XOR    DX,DX
  124. ;Set up DS and ES to point to flags segment
  125.         MOV    AX,FLAGSEG
  126.         MOV    DS,AX
  127.         MOV    ES,AX
  128. ;Set all flags to true
  129.         XOR    DI,DI
  130.         PUSH    CX        ;4/14/93 -- RG
  131.         MOV    CX,SSIZE
  132.         MOV    AL,TRUE
  133.         REP    STOSB
  134.         POP    CX        ;4/14/93 -- RG
  135. ;Do the main loop
  136.         XOR    SI,SI        ;i=0
  137. DS1:        CMP    SI,SSIZE    ;for(i=0;i<=size;...)
  138.         JG    DS5
  139.         CMP    BYTE PTR [SI],TRUE    ;if(flags[i])
  140.         JNZ    DS4A
  141.         MOV    BX,SI
  142.         ADD    BX,SI
  143.         ADD    BX,3        ;prime=i+i+3
  144. ;Inner loop
  145.         MOV    DI,BX
  146.         ADD    DI,SI        ;k=i+prime
  147. DS3:        CMP    DI,SSIZE    ;k<=size
  148.         JG    DS4
  149.         MOV    BYTE PTR [DI],FALSE
  150.         ADD    DI,BX        ;k+=prime
  151.         JMP    DS3
  152. DS4:        INC    DX        ;count++
  153. DS4A:        INC    SI        ;...i++)
  154.         JMP    DS1
  155. DS5:        MOV    AX,DX        ;Return count
  156. ;Do more sieves
  157.         LOOP    DS0        ;4/14/93 -- RG
  158. ;Restore
  159.         POP    ES
  160.         POP    DS
  161.         POP    DI
  162.         POP    SI
  163.         POP    DX
  164.         POP    CX
  165.         POP    BX
  166.         POP    BP
  167.         RET
  168. _do_sieve    ENDP
  169.  
  170. ;****************************
  171. ;       do_shell            *
  172. ;****************************
  173. ; This routine performs the shell-sort on an integer array.
  174. ; Call with:
  175. ;           do_shell(arrayseg,top)
  176. ; arrayseg is segment address of array to sort
  177. ; top is the maximum number of elements in the array
  178. ; NOTE: The array to sort MUST begin on a segment boundary.
  179. ;
  180. ; !!Sort routines have not been changed -- 4/14/93 RG
  181. ; They still take enough processor time.
  182. ;
  183.     PUBLIC    _do_shell
  184. SHARRAYSEG    equ    [BP+4]
  185. SHTOP        equ    [BP+6]
  186.  
  187. _do_shell    PROC    NEAR
  188. ;Save registers
  189.         PUSH    BP
  190.         MOV    BP,SP
  191.         PUSH    BX
  192.         PUSH    DX
  193.         PUSH    SI
  194.         PUSH    DI
  195.         PUSH    DS
  196. ;Set up data segment
  197.         MOV    AX,SHARRAYSEG
  198.         MOV    DS,AX
  199. ;Calculate the gap
  200.         MOV    BX,SHTOP        ;gap=(top-bot)/2
  201.         SHR    BX,1
  202. ;
  203. SHS1:        MOV    DL,1        ;nex=1
  204.         XOR    DI,DI        ;for(i=0...
  205. SHS2:        MOV    AX,SHTOP
  206.         SUB    AX,BX
  207.         SHL    AX,1        ;Word boundary
  208.         CMP    DI,AX        ;...;i<=top-gap
  209.         JG    SHS3
  210.         MOV    SI,DI
  211.         ADD    SI,BX        ;Word boundary
  212.         ADD    SI,BX
  213.         MOV    AX,[SI]
  214.         CMP    AX,[DI]
  215.         JGE    SHS2A
  216.         MOV    AX,[SI]        ;exchange elements
  217.         XCHG    AX,[DI]
  218.         MOV    [SI],AX
  219.         XOR    DL,DL        ;Swap has occurred
  220. SHS2A:        INC    DI
  221.         INC    DI        ;++i
  222.         JMP    SHS2
  223. SHS3:        OR    DL,DL
  224.         JZ    SHS1
  225. ;
  226.         SHR    BX,1        ;gap=gap/2
  227.         JNZ    SHS1        ;while(gap!=0)
  228. ;Restore
  229.         POP    DS
  230.         POP    DI
  231.         POP    SI
  232.         POP    DX
  233.         POP    BX
  234.         POP    BP
  235.         RET
  236. _do_shell    ENDP
  237.  
  238. ;****************************
  239. ;      do_qsort             *
  240. ;****************************
  241. ; This routine performs the quicksort algorithm on an integer array.
  242. ; Call with:
  243. ;       do_qsort(arrayseg,bot,top)
  244. ;  arrayseg is the segment of the array to sort
  245. ;  bot is to lowest element in the partition
  246. ;  top is the highest element in the partition
  247. QSTOP        equ    [BP+8]
  248. QSBOT        equ    [BP+6]
  249. QSARRAYSEG    equ    [BP+4]
  250.         PUBLIC    _do_qsort
  251. _do_qsort    PROC    NEAR
  252. ;Set up the stack
  253.         PUSH    BP
  254.         MOV    BP,SP
  255.         PUSH    DX
  256.         PUSH    SI
  257.         PUSH    DI
  258.         PUSH    DS
  259. ;Point DS register properly
  260.         MOV    AX,QSARRAYSEG
  261.         MOV    DS,AX
  262. ;while(bot<top)
  263. QS0:        MOV    AX,QSBOT
  264.         CMP    AX,QSTOP
  265.         JGE    QS6
  266. ;Set ranges and choose partitioning element
  267.         MOV    SI,AX        ;SI holds i
  268.         SHL    SI,1        ;Word align
  269.         MOV    DI,QSTOP    ;DI holds j
  270.         SHL    DI,1        ;Word align
  271.         MOV    DX,[SI]        ;temp=array[bot]
  272. ;Partition array
  273. QS1:        CMP    SI,DI        ;while(i<j)
  274.         JGE    QS5A
  275. QS2:        CMP    [DI],DX        ;while(array[j]>temp)
  276.         JLE    QS3
  277.         DEC    DI        ;j-=1
  278.         DEC    DI        ;(Word aligned)
  279.         JMP    QS2
  280. QS3:        MOV    AX,[DI]        ;array[i]=array[j]
  281.         MOV    [SI],AX
  282. QS4:        CMP    SI,DI        ;while((i<j) && ...
  283.         JGE    QS5
  284.         CMP    [SI],DX        ;...(array[i]<=temp))
  285.         JG    QS5
  286.         INC    SI        ;i+=1
  287.         INC    SI        ;(Word aligned)
  288.         JMP    QS4
  289. QS5:        MOV    AX,[SI]        ;array[j]=array[i]
  290.         MOV    [DI],AX
  291.         JMP    QS1
  292. QS5A:        MOV    [SI],DX        ;array[i]=temp
  293. ;Call qsort recursively
  294.         MOV    AX,SI
  295.         SHR    AX,1        ;Back to non-word alignment
  296.         DEC    AX
  297.         PUSH    AX
  298.         MOV    AX,QSBOT
  299.         PUSH    AX
  300.         PUSH    DS
  301.         CALL    _do_qsort
  302.         ADD    SP,6        ;Clear stack
  303.         SHR    SI,1        ;bot=i+1
  304.         INC    SI
  305.         MOV    QSBOT,SI
  306.         JMP    QS0
  307. QS6:        POP    DS        ;Restore
  308.         POP    DI
  309.         POP    SI
  310.         POP    DX
  311.         POP    BP
  312.         RET
  313. _do_qsort    ENDP
  314.  
  315. ;****************************
  316. ;       do_bmove            *
  317. ;****************************
  318. ; Byte-wide move
  319. ; Call with:
  320. ;    do_bmove(seg1,off1,seg2,off2,nbytes)
  321. ;    seg1,off1 = segment/offset of source
  322. ;    seg2,off2 = segment/offset of destination
  323. ;    nbytes = unsigned count of number of bytes to move
  324. ;
  325. ; !! Each call to this routine performs 25 iterations 4/14/93 RG
  326. ;
  327.         PUBLIC    _do_bmove
  328. _do_bmove    PROC    NEAR
  329. SEG1        equ    [BP+4]
  330. OFF1        equ    [BP+6]
  331. SEG2        equ    [BP+8]
  332. OFF2        equ    [BP+10]
  333. NBYTES        equ    [BP+12]
  334. ;Save everything
  335.         PUSH    BP
  336.         MOV    BP,SP
  337.         PUSH    BX        ;4/14/93 RG
  338.         PUSH    CX
  339.         PUSH    SI
  340.         PUSH    DI
  341.         PUSH    DS
  342.         PUSH    ES
  343. ;Set iteration count
  344.         MOV    BX,25        ;4/14/93 RG
  345. ;Load up the registers
  346. MVB0:
  347.         MOV    AX,SEG1
  348.         MOV    DS,AX
  349.         MOV    AX,SEG2
  350.         MOV    ES,AX
  351.         MOV    SI,OFF1
  352.         MOV    DI,OFF2
  353.         MOV    CX,NBYTES
  354.         CLD
  355.         REP    MOVSB
  356. ;Do more iterations
  357.         DEC    BX        ;4/14/93 RG
  358.         JNZ    MVB0        ;4/14/93 RG
  359. ;Restore and return
  360.         POP    ES
  361.         POP    DS
  362.         POP    DI
  363.         POP    SI
  364.         POP    CX
  365.         POP    BX
  366.         POP    BP
  367.         RET
  368. _do_bmove    ENDP
  369. ;****************************
  370. ;       do_wmove            *
  371. ;****************************
  372. ; Word-wide move
  373. ; Call with:
  374. ;    do_bmove(seg1,off1,seg2,off2,nwords)
  375. ;    seg1,off1 = segment/offset of source
  376. ;    seg2,off2 = segment/offset of destination
  377. ;    nwords = unsigned count of number of words to move
  378. ; !! Each call to this routine performs 25 iterations 4/14/93 RG
  379. ;
  380.         PUBLIC    _do_wmove
  381. _do_wmove    PROC    NEAR
  382. SEG1        equ    [BP+4]
  383. OFF1        equ    [BP+6]
  384. SEG2        equ    [BP+8]
  385. OFF2        equ    [BP+10]
  386. NWORDS        equ    [BP+12]
  387. ;Save everything
  388.         PUSH    BP
  389.         MOV    BP,SP
  390.         PUSH    BX        ;4/14/93 RG
  391.         PUSH    CX
  392.         PUSH    SI
  393.         PUSH    DI
  394.         PUSH    DS
  395.         PUSH    ES
  396. ;Set iteration count
  397.         MOV    BX,25        ;4/14/93 RG
  398. ;Load up the registers
  399. MVW0:
  400.         MOV    AX,SEG1
  401.         MOV    DS,AX
  402.         MOV    AX,SEG2
  403.         MOV    ES,AX
  404.         MOV    SI,OFF1
  405.         MOV    DI,OFF2
  406.         MOV    CX,NWORDS
  407.         CLD
  408.         REP    MOVSW
  409. ;Do more iterations
  410.         DEC    BX        ;4/14/93 RG
  411.         JNZ    MVB0        ;4/14/93 RG
  412. ;Restore and return
  413.         POP    ES
  414.         POP    DS
  415.         POP    DI
  416.         POP    SI
  417.         POP    CX
  418.         POP    BX        ;4/14/93 RG
  419.         POP    BP
  420.         RET
  421. _do_wmove    ENDP
  422.  
  423. ;****************************
  424. ;         do_dmove          *
  425. ;****************************
  426. ; do_dmove(seg1,off1,seg1,off2,ndwords
  427. ;
  428. ; !! This version performs 25 iteratiosn 4/14/93 RG
  429.     PUBLIC    _do_dmove
  430. _do_dmove    PROC    NEAR
  431. SEG1        equ    [BP+4]
  432. OFF1        equ    [BP+6]
  433. SEG2        equ    [BP+8]
  434. OFF2        equ    [BP+10]
  435. NDWORDS        equ    [BP+12]
  436.         PUSH    BP
  437.         MOV    BP,SP
  438.         PUSH    BX
  439.         PUSH    CX
  440.         PUSH    SI
  441.         PUSH    DI
  442.         PUSH    DS
  443.         PUSH    ES
  444. ;Set up iteration count
  445.         MOV    BX,25        ;4/14/93 rg
  446. ;Set up segments
  447. MVD0:
  448.         MOV    AX,SEG1
  449.         MOV    DS,AX
  450.         MOV    AX,SEG2
  451.         MOV    ES,AX
  452. .386
  453.         XOR    ESI,ESI
  454.         XOR    EDI,EDI
  455.         XOR    ECX,ECX
  456.         MOV    SI,OFF1
  457.         MOV    DI,OFF2
  458.         MOV    CX,NDWORDS
  459.         CLD
  460.         REP    MOVSD
  461. .8086
  462. ;Do more iterations
  463.         DEC    BX        ;4/14/93 rg
  464.         JNZ    MVD0        ;4/14/93 rg
  465. ;Restore and return
  466.         POP    ES
  467.         POP    DS
  468.         POP    DI
  469.         POP    SI
  470.         POP    CX
  471.         POP    BX
  472.         POP    BP
  473.         RET
  474. _do_dmove    ENDP
  475.  
  476. ;****************************
  477. ;      do_ifourbang         *
  478. ;****************************
  479. ; do_ifourbang(ifacseg,numvals)
  480. ; !!This version performs 10 iterations 4/14/93 RG
  481.     PUBLIC    _do_ifourbang
  482. _do_ifourbang    PROC    NEAR
  483. IFACSEG        equ    [BP+4]
  484. NUMVALS        equ    [BP+6]
  485.         PUSH    BP
  486.         MOV    BP,SP
  487.         PUSH    BX
  488.         PUSH    CX
  489.         PUSH    DX        ;4/14/93 RG
  490.         PUSH    SI
  491.         PUSH    DS
  492. ;Set up loop count
  493.         MOV    DX,10        ;4/14/93 rg
  494. ;Load up registers
  495. IFB0:
  496.         PUSH    DX        ;4/14/93 rg
  497.         MOV    AX,IFACSEG
  498.         MOV    DS,AX
  499.         MOV    CX,NUMVALS
  500. ;Start the loop
  501.         XOR    SI,SI
  502.         MOV    BX,8
  503.         XOR    AX,AX
  504. IFB1:        ADD    AX,[SI]
  505.         SUB    AX,[SI+2]
  506.         IMUL    WORD PTR [SI+4]
  507.         IDIV    WORD PTR [SI+6]
  508.         ADD    SI,BX
  509.         LOOP    IFB1
  510. ;Do more iterations
  511.         POP    DX        ;4/14/93 rg
  512.         DEC    DX        ;4/14/93 rg
  513.         JNZ    IFB0        ;4/14/93 rg
  514. ;Go home
  515.         POP    DS
  516.         POP    SI
  517.         POP    DX
  518.         POP    CX
  519.         POP    BX
  520.         POP    BP
  521.         RET
  522. _do_ifourbang    ENDP
  523. .8087
  524. ;****************************
  525. ;     init_fpu              *
  526. ;****************************
  527. ; Initialize FPU
  528.     PUBLIC    _init_fpu
  529. _init_fpu    PROC    NEAR
  530.         FINIT
  531.         RET
  532. _init_fpu    ENDP
  533. ;****************************
  534. ;       do_fourbang         *
  535. ;****************************
  536. ; This routine performs the floating-point "four-banger" test.
  537. ; Call with:
  538. ;    do_fourbang(iterations)
  539. ;    uint iterations
  540. ; Where:
  541. ;   Iterations is the number of times to repeat the loop
  542.         PUBLIC    _do_fourbang
  543. NFOURBANGS    equ    [BP+4]
  544. _do_fourbang    PROC    NEAR
  545.         PUSH    BP
  546.         MOV    BP,SP
  547. ;See what kind of coprocessor
  548.         MOV    AX, coproc
  549.         PUSH    DS        ;Swap segment
  550.         MOV    BX,FDATA
  551.         MOV    DS,BX
  552.         CMP    AX,1
  553.         JG      FNLP        ;Do no-waits
  554. ASSUME    DS:FDATA
  555. ;Initialize the result field
  556.         FLDZ
  557.         FSTP    QWORD PTR FRESULT
  558. ;Load loop count
  559.         MOV    CX,NFOURBANGS
  560. ;Do the loops
  561. FLP1:
  562.         FLD    QWORD PTR FRESULT
  563.         FLD    QWORD PTR FAC1
  564.         FADD
  565.         FLD    QWORD PTR FAC2
  566.         FSUB
  567.         FLD    QWORD PTR FAC3
  568.         FMUL
  569.         FLD    QWORD PTR FAC4
  570.         FDIV
  571.         FSTP    QWORD PTR FRESULT
  572.         LOOP    FLP1
  573. ;Return
  574.         POP    DS
  575.         POP    BP
  576.         RET
  577. .387
  578. FNLP:
  579.         FLDZ
  580.         FSTP   QWORD PTR FRESULT
  581.         MOV    CX,NFOURBANGS
  582.         EVEN
  583. FNLP1:          FLD    QWORD PTR FRESULT
  584.         FLD    QWORD PTR FAC1
  585.         FADD
  586.         FLD    QWORD PTR FAC2
  587.         FSUB
  588.         FLD    QWORD PTR FAC3
  589.         FMUL
  590.         FLD    QWORD PTR FAC4
  591.         FDIV
  592.         FSTP    QWORD PTR FRESULT
  593.         LOOP    FNLP1
  594.         POP    DS
  595.         POP    BP
  596.         RET
  597. _do_fourbang    ENDP
  598.  
  599. .8087
  600. ASSUME DS:_DATA
  601. ;****************************
  602. ;     square_fourier        *
  603. ;****************************
  604. ; Fourier series for a square wave of period 2
  605. ; Call with:
  606. ;    square_fourier(ncoeff,coeffarray)
  607. ;    ncoeff = number of coefficients
  608. ;    coeffarray = array of doubles holding results
  609. ; NOte that since the period is 2, omega is 2*pi/period = pi.
  610. ; Knowing this, we advance the i*omega by simply adding pi
  611. ; to that variable on each pass.
  612. ; Hey, it works.
  613. ;
  614. ;!!This version performs 25 iterations.
  615. STEPSIZE    equ    501
  616.     PUBLIC    _square_fourier
  617. NCOEFF        equ    [BP+4]
  618. COEFFARRAY    equ    [BP+6]
  619. _square_fourier    PROC    NEAR
  620.         PUSH    BP
  621.         MOV    BP,SP
  622.         PUSH    SI
  623.         PUSH    DX        ;4/14/93 RG
  624. ;Set loop count
  625.         MOV    DX,25
  626. SQF0:
  627.         MOV    CX,NCOEFF    ;Get # of coefficients
  628.         MOV    SI,COEFFARRAY    ;Pointer to array
  629. ;First calculate a0
  630.         PUSH    CX
  631.         MOV    CX,STEPSIZE    ;Stepsize
  632.         MOV    BX,OFFSET square_wave
  633.         FLD1
  634.         FLD1
  635.         FADD            ;Upper integration limit
  636.         FLDZ            ;Lover limit
  637.         CALL    do_trapezoid    ;Integrate
  638.         FLD1
  639.         FLD1
  640.         FADD
  641.         FDIV            ;Result/2 = a0
  642.         FSTP    QWORD PTR [SI]    ;Save a0
  643.         ADD    SI,4        ;Bump pointer
  644.         POP    CX
  645. ;Set up iw (i omega)
  646.         FLDPI
  647.         FSTP    QWORD PTR IOMEGA
  648. ;Calculate remaining a(i) coefficients
  649. SQF1:        PUSH    CX        ;Save loop counter
  650.         MOV    CX,STEPSIZE    ;Stepsize
  651.         MOV    BX,OFFSET square_cosine
  652.         FLD1
  653.         FLD1
  654.         FADD            ;Upper limit
  655.         FLDZ            ;Lower limit
  656.         CALL    do_trapezoid
  657.         FSTP    QWORD PTR [SI]    ;Store a(i) coefficient
  658.         ADD    SI,4        ;Bump pointer
  659. ;Calculate remaining b(i) coefficients
  660.         MOV    CX,STEPSIZE    ;Intervals
  661.         MOV    BX,OFFSET square_sine
  662.         FLD1
  663.         FLD1
  664.         FADD            ;Upper limit
  665.         FLDZ            ;Lower limit
  666.         CALL    do_trapezoid
  667.         FSTP    QWORD PTR [SI]    ;Store b(i) coefficient
  668.         ADD    SI,4
  669. ;Incremenmt iomega
  670.         FLDPI
  671.         FADD    QWORD PTR IOMEGA
  672.         FSTP    QWORD PTR IOMEGA
  673. ;See if the loop is finished
  674.         POP    CX
  675.         LOOP    SQF1
  676. ;Do more iterations
  677.         DEC    DX        ;4/14/93 rg
  678.         JZ    SQFX
  679.         JMP    SQF0
  680. ;All done - restore
  681. SQFX:
  682.         POP    DX
  683.         POP    SI
  684.         POP    BP
  685.         RET
  686. _square_fourier    ENDP
  687.  
  688. ;****************************
  689. ;     square_wave           *
  690. ;****************************
  691. ; A square wave of period 2.  Valid from x=0.0 to x<2.0
  692. ; Wave amplitude is +1/-1
  693. ; On entry:
  694. ;    ST(0)=x
  695. ; On exit
  696. ;    ST(0)=f(x)
  697. square_wave:
  698.     FLD1                ;Get a 1.0 on top
  699.     FCOM                ;See where x is
  700.     FSTSW    FSTATUS
  701.     FWAIT
  702.     MOV    AX,FSTATUS
  703.     AND    AH,01000101B        ;Get condition bits
  704.     FSTP    ST(1)            ;Discard x
  705.     CMP    AH,1
  706.     JNE    SQC2
  707. ;x>1 - return a -1
  708.     FCHS                ;1.0 is now -1.0
  709. SQC2:
  710.     RET
  711.  
  712. ;****************************
  713. ;     square_cosine         *
  714. ;****************************
  715. ; Returns cosine component for fourier series.
  716. ; On entry:
  717. ;     ST(0) = x
  718. ;     IOMEGA = iw
  719. ; On exit:
  720. ;     ST(0) = f(x) * cos(iwx)
  721. ; Where f(x) is a square wave of period 2.
  722. square_cosine:
  723.     FLD    ST(0)            ;Dup x
  724.     FMUL    QWORD PTR IOMEGA        ;iw * x
  725.     CALL    calc_cosine        ;Get cosine of ST(0)
  726. SQC1:    FXCH                ;Swap
  727.     CALL    square_wave        ;Get f(x) on top
  728.     FMUL                ;f(x) * cos(iwx)
  729.     RET
  730.  
  731. ;****************************
  732. ;      square_sine          *
  733. ;****************************
  734. ; On entry:
  735. ;     ST(0) = x
  736. ;     IOMEGA = iw
  737. ; On exit:
  738. ;     ST(0) = f(x) * sin(iwx)
  739. ; Where f(x) is a square wave of period 2.
  740. square_sine:
  741.     FLD    ST(0)            ;Dup x
  742.     FMUL    QWORD PTR IOMEGA    ;iw * x
  743.     CALL    calc_sine        ;sin(iwx)
  744.     JMP    SQC1            ;Link to common code
  745.  
  746. ;****************************
  747. ;      do_trapezoid         *
  748. ;****************************
  749. ; On entry:
  750. ;     CX = number of intervals for integration
  751. ;     BX = pointer to routine that will push the value of f(x)
  752. ;          on the FPU stack.  x will be stored in ST(0).
  753. ;     ST(0) = Lower limit of integration
  754. ;     ST(1) = upper limit of integration
  755. ; On exit:
  756. ;     ST(0) holds value of integration formula
  757. do_trapezoid    PROC    NEAR
  758. ;Save the starting value of x
  759.         FST    QWORD PTR STARTX
  760. ;Calculate the increment width
  761.         FSUB            ;top - bottom
  762.         MOV    FSTATUS,CX    ;Borrow FSTATUS field
  763.         FILD    WORD PTR FSTATUS ;Get n (number of intervals)
  764.         FDIV            ;dx=(top-bottom)/n
  765. ;Get f(bottom)
  766.         FLD    QWORD PTR STARTX
  767.         CALL    BX        ;Call f(x)
  768.         FLD1
  769.         FADD    ST(0),ST    ;Calculate 2.0
  770.         FDIV            ;f(x0)/2
  771.         FXCH    ST(1)        ;-- f(x0)/2 dx
  772.         FLD    QWORD PTR STARTX ; -- f(x0)/2 dx x
  773. ; Stack is now x, dx, f(x0)/2
  774. ; Begin the loop
  775.         DEC    CX
  776. FINTEG1:
  777.         FADD    ST,ST(1)    ;x'=x+dx
  778.         FLD    ST(0)        ;DUP x'
  779.         CALL    BX        ;Get f(x')
  780.         FADDP    ST(3),ST    ;Accumulate and pop f(x)
  781.         LOOP    FINTEG1
  782. ;Calculate f(x)/2 x=endpoint
  783.         FADD    ST,ST(1)
  784.         CALL    BX
  785.         FLD1
  786.         FADD    ST(0),ST
  787.         FDIV            ;Divide by 2
  788.         FADDP    ST(2),ST    ;Accumulate
  789.         FMUL            ;Times dx
  790. ;Return
  791.         RET
  792. do_trapezoid    ENDP
  793.  
  794.  
  795. ;****************************
  796. ;        calc_cosine        *
  797. ;****************************
  798. ; On entry:
  799. ;       x is stored in ST(0)
  800. ; On exit
  801. ;       cosine(x) is stored in ST(0)
  802. ; This routine uses the identities:
  803. ;   cos(x) = cos(x + pi/2)
  804. ;   cos(x) = cos(|x|)
  805. calc_cosine:
  806.     FLD    PIDIV2        ;Load pi/2
  807.     FADDP    ST(1),ST(0)    ;Add to x
  808.     FABS            ;Take absolute value
  809.     CALL    calc_sine
  810.     RET
  811.  
  812. ;****************************
  813. ;        calc_sine          *
  814. ;****************************
  815. ; On entry:
  816. ;    x is stored in ST(0)
  817. ; On exit
  818. ;    sine(x) is stored in ST(0).
  819. ; NOTE: This routine is based on the floating-point routines
  820. ; found in the public-domain FORTH system ABUNDANCE.
  821. calc_sine:
  822.     MOV    AX,coproc
  823.     CMP    AX,3        ;80387?
  824.     JNZ    CSIN0
  825.     JMP    SIN387
  826. CSIN0:
  827.     PUSH    BX
  828.     PUSH    CX
  829.     PUSH    DX
  830.     XOR    DX,DX        ;Clear DX
  831.     FTST
  832.     FSTSW    FSTATUS        ;Store status word
  833.     FWAIT
  834.     MOV    AX,FSTATUS
  835.     SAHF            ;Status in flags
  836.     JAE    CSIN1
  837.     MOV    DL,0FFH        ;Indicate negative
  838.     FABS
  839. ;Set ST(0) between 0 and pi/4
  840. CSIN1:    FLD    DWORD PTR MINUS2
  841.     FLDPI
  842.     FSCALE
  843.     FSTP    ST(1)
  844.     FXCH    ST(1)
  845. CSIN2:    FPREM
  846.     FSTSW    FSTATUS
  847.     FWAIT
  848.     MOV    AX,FSTATUS
  849.     SAHF
  850.     JP    CSIN2        ;Jump if C2!=0
  851.     FTST
  852.     FSTSW    FSTATUS
  853.     FWAIT
  854.     XOR    BX,BX
  855.     AND    FSTATUS,4100H
  856.     MOV    CX,FSTATUS
  857.     CMP    CH,40H
  858.     JNZ    CSIN3
  859.     DEC    BX        ;BX=-1
  860. CSIN3:    TEST    AH,2
  861.     JNZ    CSIN5
  862.     FSTP    ST(1)
  863.     OR    BX,BX
  864.     JZ    CSIN4
  865.     FSTP    ST(0)
  866.     FLDZ
  867.     FLD1
  868.     JMP    CSIN7
  869. CSIN4:    FPTAN
  870.     JMP    CSIN7
  871. CSIN5:    OR    BX,BX
  872.     JNZ    CSIN6
  873.     FSUBP    ST(1),ST(0)
  874.     FPTAN
  875.     JMP    CSIN7
  876. CSIN6:    FSTP    ST(0)
  877.     FSTP    ST(0)
  878.     FLD1
  879.     FLD1
  880. CSIN7:    XOR    BX,BX
  881.     TEST    AH,40H
  882.     JZ    CSIN8
  883.     INC    BX        ;BX=1
  884. CSIN8:    TEST    AH,2
  885.     JZ    CSIN9
  886.     XOR    BX,1
  887.     JMP    CSIN10
  888. CSIN9:
  889. CSIN10:    CMP    BX,1
  890.     JNZ    CSIN11
  891.     FXCH    ST(1)
  892. CSIN11:    FMUL    ST(0),ST(0)
  893.     FLD    ST(1)
  894.     FMUL    ST(0),ST(0)
  895.     FADDP    ST(1),ST(0)
  896.     FSQRT
  897.     FDIVP    ST(1),ST(0)
  898.     TEST    AH,1
  899.     JZ    CSIN12
  900.     NOT    DL
  901. CSIN12:    OR    DL,DH
  902.     JZ    CSIN13
  903.     FCHS
  904. CSIN13:    POP    DX
  905.     POP    CX
  906.     POP    BX
  907.     RET
  908.  
  909. .387
  910. ;**************************************
  911. ;          sine387                    *
  912. ;**************************************
  913. ; Sine routine for 80387
  914. sin387:    FSIN
  915. ;    FSTP    ST(0)
  916.     RET
  917.  
  918. ;**************************************
  919. ;          GRAPHICS BENCHMARKS        *
  920. ;**************************************
  921.  
  922. ;**************************************
  923. ;           random_text               *
  924. ;**************************************
  925. ; Call with:
  926. ;    random_text(rcseg,attrseg,n,vpage)
  927. ; Where:
  928. ;    rcseg = points to array containing row,col coordinate
  929. ;            pairs (column in lo byte, row in high)
  930. ;    attrseg = points to array containing attribute
  931. ;            bytes
  932. ;    nbytes = number of entries
  933. ;    vpage = video page address
  934. ;
  935. ; !!This version performs 20 iterations
  936. ;
  937.     PUBLIC    _random_text
  938. RTEXTRCSEG    equ    [BP+4]
  939. RTEXTATTRSEG    equ    [BP+6]
  940. RTEXTN        equ    [BP+8]
  941. RTEXTVPAGE    equ    [BP+10]
  942. _random_text    PROC    NEAR
  943.         PUSH    BP
  944.         MOV    BP,SP
  945.         PUSH    BX
  946.         PUSH    CX
  947.         PUSH    DX
  948.         PUSH    SI
  949.         PUSH    DI
  950.         PUSH    DS
  951.         PUSH    ES
  952. ; Set iteration counter
  953.         MOV    CX,20
  954. ; Load up segment registers
  955. RTXT0:
  956.         PUSH    CX
  957.         MOV    AX,RTEXTRCSEG
  958.         MOV    DS,AX
  959.         XOR    SI,SI
  960.         MOV    AX,RTEXTATTRSEG
  961.         MOV    ES,AX
  962.         XOR    DI,DI
  963. ;Set count and video page
  964.         MOV    CX,RTEXTN
  965.         MOV    BX,RTEXTVPAGE
  966.         MOV    BH,BL
  967. ;Initialize character
  968.         MOV    AL,'A'
  969. ;Do it
  970. RTXT1:        PUSH    CX
  971.         MOV    DX,[SI]
  972.         MOV    AH,02H
  973.         PUSH    AX
  974.         INT    10H        ;Position cursor
  975.         POP    AX
  976.         MOV    BL,ES:[DI]
  977.         MOV    CX,1
  978.         MOV    AH,09H
  979.         INT    10H        ;Write the character
  980.         INC    SI        ;Bump pointers
  981.         INC    SI
  982.         INC    DI
  983.         INC    AL
  984.         CMP    AL,'['
  985.         JNZ    RTXT2
  986.         MOV    AL,'A'
  987. RTXT2:        POP    CX
  988.         LOOP    RTXT1
  989. ;Do outer loops
  990.         POP    CX
  991.         LOOP    RTXT0
  992. ;Done
  993.         POP    ES
  994.         POP    DS
  995.         POP    DI
  996.         POP    SI
  997.         POP    DX
  998.         POP    CX
  999.         POP    BX
  1000.         POP    BP
  1001.         RET
  1002. _random_text    ENDP
  1003.  
  1004. ;****************************
  1005. ;         scroll_text       *
  1006. ;****************************
  1007. ; Benchmark for text scrolling
  1008. ;  Call with:
  1009. ;     scroll_text(rcaseg,n,vpage)
  1010. ;  Where:
  1011. ;     rcaseg = segment holding array of row/col/attrib coordinates
  1012. ;     n = number of iterations
  1013. ;     vpage = video page
  1014. ; This benchmark reads the rcseg array 4 elements at a time.
  1015. ; The first elements holds the row/column coordinates of the
  1016. ;  upper left corner of the rectangle to scroll, while the
  1017. ;  second holds the lower right corner coordinates.
  1018. ; The third element holds the number of lines to scroll
  1019. ; The fourth holds attribute bytes used for the background fill
  1020. ; We assume you've loaded the screen up with stuff before you
  1021. ;  call this routine.
  1022. ;
  1023. ; !!This version performs 20 iterations 4/14/93 RG
  1024. ;
  1025.     PUBLIC    _scroll_text
  1026. SCLTXRCASEG    equ    [BP+4]
  1027. SCLTXN        equ    [BP+6]
  1028. SCLTXVPAGE    equ    [BP+8]
  1029. _scroll_text     PROC    NEAR
  1030.         PUSH    BP
  1031.         MOV    BP,SP
  1032.         PUSH    BX
  1033.         PUSH    CX
  1034.         PUSH    DX
  1035.         PUSH    SI
  1036.         PUSH    DS
  1037. ;Set up iterations
  1038.         MOV    CX,20
  1039. ;Set up the segment
  1040. STXT0:
  1041.         PUSH    CX
  1042.         MOV    AX,SCLTXRCASEG
  1043.         MOV    DS,AX
  1044.         XOR    SI,SI
  1045. ;Get iteration count
  1046.         MOV    CX,SCLTXN
  1047. ;Get video page
  1048.         MOV    BX,SCLTXVPAGE
  1049. ;Do it
  1050. SCLTX1:        PUSH    CX
  1051. ;Scroll up
  1052.         MOV    CX,[SI]        ;Upper left corner
  1053.         MOV    DX,[SI+2]    ;Lowr right corner
  1054.         MOV    AL,[SI+4]    ;# of lines
  1055.         MOV    BH,[SI+5]    ;Attribute
  1056.         MOV    AH,06H
  1057.         INT    10H
  1058. ;Fill up blank area
  1059. ;**NOTE: I use [SI+4] in the next line instead of AL, because INT 10H,
  1060. ;function 6 on the Model 80 munges AL.  Go figure. --rg
  1061.         ADD    CH,[SI+4]    ;Modify ulc
  1062.         XCHG    BH,BL
  1063.         MOV    AL,'A'
  1064.         CALL    FILL_RECT
  1065. ;Scroll down
  1066.         XCHG    BH,BL
  1067.         ADD    SI,6
  1068.         MOV    CX,[SI]        ;Upper left corner
  1069.         MOV    DX,[SI+2]    ;Lower right corner
  1070.         MOV    AL,[SI+4]    ;# of lines
  1071.         MOV    BH,[SI+5]    ;Attribute
  1072.         MOV    AH,07H
  1073.         INT    10H
  1074. ;Fill up blank area
  1075.         SUB    DH,[SI+4]    ;MOdify lower right corner
  1076.         XCHG    BH,BL
  1077.         MOV    AL,'B'
  1078.         CALL    FILL_RECT
  1079. ;See if we're done
  1080.         XCHG    BH,BL
  1081.         ADD    SI,6
  1082.         POP    CX
  1083.         LOOP    SCLTX1
  1084. ;Do outer loops
  1085.         POP    CX
  1086.         LOOP    STXT0
  1087. ;Go home
  1088.         POP    DS
  1089.         POP    SI
  1090.         POP    DX
  1091.         POP    CX
  1092.         POP    BX
  1093.         POP    BP
  1094.         RET
  1095. _scroll_text    ENDP
  1096.  
  1097. ;Fill_rect
  1098. ; Called by the scroll routine to fill the blank lines created
  1099. ; when a window is scrolled.
  1100. ; On entry:
  1101. ;  CH,CL = row/column of ulhc of rectangle
  1102. ;  DH,CL = row/column of lrhc of rectangle
  1103. ;  AL = character to write
  1104. ;  BL = attribute
  1105. ;  BH = video page
  1106. FILL_RECT    PROC    NEAR
  1107. ;Calculate number of columns
  1108.         MOV    AH,DL
  1109.         SUB    AH,CL
  1110.         INC    AH
  1111.         MOV    DL,CL
  1112. FRECT1:        CMP    DH,CH
  1113.         JA    FRECT2
  1114.         RET
  1115. FRECT2:
  1116.         PUSH    AX
  1117. ;Set cursor
  1118.         MOV    AH,2
  1119.         INT    10H
  1120. ;Write characters
  1121.         POP    AX
  1122.         PUSH    CX
  1123.         MOV    CL,AH
  1124.         XOR    CH,CH
  1125.         MOV    AH,9
  1126.         INT    10H
  1127.         MOV    AH,CL
  1128.         POP    CX
  1129. ;Increment location
  1130.         DEC    DH
  1131.         JMP    FRECT1
  1132. FILL_RECT    ENDP
  1133.  
  1134. ;****************************
  1135. ;        draw_circle        *
  1136. ;****************************
  1137. ; Call with:
  1138. ;  draw_circle (cx,cy,r,color,mode,esseg)
  1139. ; Where:
  1140. ;    cx,cy are coordinates of center
  1141. ;    r is circle radius in pixels
  1142. ;    color is color
  1143. ;    mode is current graphics mode
  1144. ;    esseg is graphics segment
  1145.     PUBLIC    _draw_circle
  1146. DCX        equ    [BP+4]
  1147. DCY        equ    [BP+6]
  1148. DCR        equ    [BP+8]
  1149. DCCOLOR        equ    [BP+10]
  1150. DCMODE        equ    [BP+12]
  1151. DCESSEG        equ    [BP+14]
  1152. _draw_circle    PROC    NEAR
  1153.         PUSH    BP
  1154.         MOV    BP,SP
  1155.         PUSH    BX
  1156.             PUSH    CX
  1157.         PUSH    DX
  1158.         PUSH    SI
  1159.         PUSH    DI
  1160.         PUSH    ES
  1161. ;Set up graphics segment
  1162.         MOV    AX,DCESSEG
  1163.         MOV    ES,AX
  1164. ;Do initial 4 corners
  1165.         MOV    AX,DCY        ;Initial y coord
  1166.         MOV    BX,DCX        ;Initial x coord
  1167.         ADD    BX,DCR        ;add radius
  1168.         MOV    CX,DCMODE
  1169.         MOV    DX,DCCOLOR
  1170.         CALL    SETPIXEL        ;One corner
  1171.         MOV    BX,DCX
  1172.         SUB    BX,DCR
  1173.         CALL    SETPIXEL        ;another
  1174.         MOV    BX,DCX
  1175.         ADD    AX,DCR
  1176.         CALL    SETPIXEL        ;Another
  1177.         MOV    AX,DCY
  1178.         SUB    AX,DCR
  1179.         CALL    SETPIXEL        ;And another
  1180. ;Do arc from 0 to 45 degrees and reflect
  1181.         MOV    SI,DCR        ;x offset
  1182.         XOR    DI,DI        ;y offset
  1183.         MOV    DX,DI        ;rate of change
  1184. DRC1:        ADD    DX,DI        ;dv=dv+y+y+1
  1185.         ADD    DX,DI
  1186.         INC    DX
  1187.         INC    DI        ;y+=1
  1188.         CMP    DX,SI        ;dv>x?
  1189.         JLE    DRC2
  1190.         SUB    DX,SI        ;dv=dv-x-x+1
  1191.         SUB    DX,SI
  1192.         INC    DX
  1193.         DEC    SI        ;x-=1
  1194. ;Now do reflections
  1195. DRC2:        PUSH    DX        ;Save rate of change
  1196.         MOV    DX,DCCOLOR    ;Reload color
  1197.         MOV    AX,DCY
  1198.         MOV    BX,DCX
  1199.         ADD    BX,SI
  1200.         ADD    AX,DI
  1201.         CALL    SETPIXEL
  1202.         SUB    AX,DI
  1203.         SUB    AX,DI
  1204.         CALL    SETPIXEL
  1205.         SUB    BX,SI
  1206.         SUB    BX,SI
  1207.         CALL    SETPIXEL
  1208.         ADD    AX,DI
  1209.         ADD    AX,DI
  1210.         CALL    SETPIXEL
  1211. ;If x!=y, do other reflections
  1212.         CMP    SI,DI
  1213.         JZ    DRC3
  1214.         MOV    AX,DCY
  1215.         MOV    BX,DCX
  1216.         ADD    AX,SI
  1217.         ADD    BX,DI
  1218.         CALL    SETPIXEL
  1219.         SUB    AX,SI
  1220.         SUB    AX,SI
  1221.         CALL    SETPIXEL
  1222.         SUB    BX,DI
  1223.         SUB    BX,DI
  1224.         CALL    SETPIXEL
  1225.         ADD    AX,SI
  1226.         ADD    AX,SI
  1227.         CALL    SETPIXEL
  1228. ;See if done
  1229. DRC3:        POP    DX        ;Restore rate of change
  1230.         CMP    DI,SI        ;y=x?
  1231.         JB    DRC1
  1232. ;Go home
  1233.         POP    ES
  1234.         POP    DI
  1235.         POP    SI
  1236.         POP    DX
  1237.         POP    CX
  1238.         POP    BX
  1239.         POP    BP
  1240.         RET
  1241. _draw_circle    ENDP
  1242.  
  1243. ;****************************
  1244. ;      do_flood             *
  1245. ;****************************
  1246. ; Call with:
  1247. ;   do_flood(x,y,color,mode,floodseg,esseg)
  1248. ;    x,y coordinates within bounded region to flood
  1249. ;    color - color to flood with
  1250. ;    mode - graphics mode
  1251. ;    floodseg - use in place of recursive calls; this is
  1252. ;               the pointer to a segment where intermediate
  1253. ;               values will be stored
  1254. ;    esseg - graphics segment
  1255. ; NOTE: This fellow does NOT check for out-of-screen bounds
  1256. ;  condition.  Region MUST be bounded.
  1257.     PUBLIC    _do_flood
  1258. DOFLX        equ    [BP+4]
  1259. DOFLY        equ    [BP+6]
  1260. DOFLCOLOR    equ    [BP+8]
  1261. DOFLMODE    equ    [BP+10]
  1262. DOFLSEG        equ    [BP+12]
  1263. DOFLESSEG    equ    [BP+14]
  1264. _do_flood    PROC    NEAR
  1265.         PUSH    BP
  1266.         MOV    BP,SP
  1267.         PUSH    BX
  1268.         PUSH    CX
  1269.         PUSH    DX
  1270.         PUSH    SI
  1271.         PUSH    DS
  1272.         PUSH    ES
  1273. ;Set segment for temporaries
  1274.         MOV    AX,DOFLSEG
  1275.         MOV    DS,AX
  1276. ;Set up graphics segment
  1277.         MOV    AX,DOFLESSEG
  1278.         MOV    ES,AX
  1279.         XOR    SI,SI
  1280. ;Initialize coordinates and stuff
  1281.         MOV    BX,DOFLX
  1282.         MOV    AX,DOFLY
  1283.         MOV    CX,DOFLMODE
  1284. ;Set current pixel
  1285. DOFL1:        MOV    DX,DOFLCOLOR
  1286.         CALL    SETPIXEL
  1287. ;See if pixel above is filled
  1288.         DEC    AX
  1289.         CALL    TESTNPUSH
  1290. ;See if pixel to right is filled
  1291.         INC    AX
  1292.         INC    BX
  1293.         CALL    TESTNPUSH
  1294. ;See if pixel below is filled
  1295.         INC    AX
  1296.         DEC    BX
  1297.         CALL    TESTNPUSH
  1298. ;See if pixel to left is filled
  1299.         DEC    AX
  1300.         DEC    BX
  1301.         CALL    TESTNPUSH
  1302. ;Anything on pixel stack?
  1303.         OR    SI,SI
  1304.         JZ    DOFL9
  1305. ;Something there...fetch and loop
  1306.         SUB    SI,4
  1307.         MOV    AX,[SI]
  1308.         MOV    BX,[SI+2]
  1309.         JMP    DOFL1
  1310. ;Go home
  1311. DOFL9:
  1312.         POP    ES
  1313.         POP    DS
  1314.         POP    SI
  1315.         POP    DX
  1316.         POP    CX
  1317.         POP    BX
  1318.         POP    BP
  1319.         RET
  1320. _do_flood    ENDP
  1321.  
  1322. ; TESTNPUSH
  1323. ; This routine is used by do_flood to see if a pixel should
  1324. ; be filled.  If the pixel qualified, it is "pushed" onto a
  1325. ; pixel stack pointed to by DS:SI
  1326. TESTNPUSH    PROC    NEAR
  1327.         PUSH    SI        ;Save
  1328.         CALL    GETP        ;Get pixel's color
  1329.         POP    SI
  1330.         XOR    DH,DH        ;Clear hi byte
  1331.         CMP    DX,DOFLCOLOR    ;Match?
  1332.         JZ    TNPX        ;Already filled if match
  1333.         MOV    [SI],AX        ;Push y coordinate
  1334.         MOV    [SI+2],BX    ;Push x coordinate
  1335.         ADD    SI,4        ;Increment "stack" pointer
  1336. TNPX:        RET
  1337. TESTNPUSH    ENDP
  1338.  
  1339. ;**************************************
  1340. ;            DISK BENCHMARKS          *
  1341. ;**************************************
  1342.  
  1343. ;****************************
  1344. ;     rand_cyl_seek         *
  1345. ;****************************
  1346. ; Random cylinder seek benchmark.
  1347. ; Call with:
  1348. ;   rand_cyl_seek(arrayseg,size,buffseg,drivenum)
  1349. ; Where:
  1350. ;    arrayseg = pointer to segment holding array of random
  1351. ;               integers
  1352. ;    size = number of elements in the array
  1353. ;    buffseg = pointer to segment that will be the read buffer
  1354. ;              (In this case, 512 bytes is all you need )
  1355. ;    drivenum = drive number (0=first fixed disk, 1=second)
  1356. ; NOTE: Elements in arrayseg must already be in cylinder/sector
  1357. ;       format.
  1358.         PUBLIC    _rand_cyl_seek
  1359. RCYLARRAYSEG    equ    [BP+4]
  1360. RCYLARRAYSIZE    equ    [BP+6]
  1361. RCYLBUFFSEG    equ    [BP+8]
  1362. RCYLDRIVE    equ    [BP+10]
  1363. _rand_cyl_seek    PROC    NEAR
  1364.         PUSH    BP
  1365.         MOV    BP,SP
  1366.         PUSH    BX
  1367.         PUSH    CX
  1368.         PUSH    DX
  1369.         PUSH    SI
  1370.         PUSH    ES
  1371.         PUSH    DS
  1372. ;Load count
  1373.         MOV    CX,RCYLARRAYSIZE
  1374. ;Load segment of random numbers and initialize pointer
  1375.         MOV    AX,RCYLARRAYSEG
  1376.         MOV    DS,AX
  1377.         XOR    SI,SI
  1378. ;Load the buffer segment
  1379.         MOV    AX,RCYLBUFFSEG
  1380.         MOV    ES,AX
  1381.         XOR    BX,BX
  1382. ;Load drive and head number
  1383.         MOV    DX,RCYLDRIVE
  1384.         OR    DL,80H
  1385.         XOR    DH,DH
  1386. ;Do it
  1387. RCYL1:        PUSH    CX        ;Save loop count
  1388.         MOV    CX,[SI]        ;Get cylinder
  1389.         MOV    AH,2
  1390.         MOV    AL,1        ;1 sector
  1391.         INT     13H
  1392.         POP    CX
  1393.         JC    RCYLE        ;Bum out if error
  1394.         INC    SI
  1395.         INC    SI
  1396.         LOOP    RCYL1
  1397.         XOR    AX,AX        ;show all ok
  1398. RCYLX:        POP    DS
  1399.         POP    ES
  1400.         POP    SI
  1401.         POP    DX
  1402.         POP    CX
  1403.         POP    BX
  1404.         POP    BP
  1405.         RET
  1406. RCYLE:        MOV    AL,AH        ;Move error to lo byte
  1407.         XOR    AH,AH
  1408.         JMP    RCYLX        ;Return with error
  1409. _rand_cyl_seek    ENDP
  1410.  
  1411. ;****************************
  1412. ;        hd_rread           *
  1413. ;****************************
  1414. ; Hard disk random read benchmark.
  1415. ; This test performs a series of seeks to sector 1 head 0
  1416. ; for the random cylinder numbers held in arrayseg.
  1417. ;  Call with:
  1418. ;    hd_rread(drive,arrayseg,buffseg,n)
  1419. ;  Where:
  1420. ;    drive = drive number
  1421. ;    arrayseg = segment of array of random cylinder numbers
  1422. ;    nsecseg= number of sectors segment
  1423. ;    buffseg = segment to act as read buffer
  1424. ;    n = number of iterations
  1425. ; Returns nonzero error code if something happened, else
  1426. ; returns error.
  1427.     PUBLIC    _hd_rread
  1428. HDDRIVE        equ    [BP+4]
  1429. HDARRAYSEG    equ    [BP+6]
  1430. HDBUFFSEG    equ    [BP+8]
  1431. HDN        equ    [BP+10]
  1432. _hd_rread    PROC    NEAR
  1433.         PUSH    BP
  1434.         MOV    BP,SP
  1435.         PUSH    BX
  1436.         PUSH    CX
  1437.         PUSH    DX
  1438.         PUSH    SI
  1439.         PUSH    DS
  1440.         PUSH    ES
  1441. ;Load count
  1442.         MOV    CX,HDN
  1443. ;Load segment of random numbers and initialize pointer
  1444.         MOV    AX,HDARRAYSEG
  1445.         MOV    DS,AX
  1446.         XOR    SI,SI
  1447. ;Fix buffer pointer
  1448.         MOV    AX,HDBUFFSEG
  1449.         MOV    ES,AX
  1450.         XOR    BX,BX
  1451. ;Load drive number
  1452.         MOV    DX,HDDRIVE
  1453.         XOR    DH,DH
  1454. ;Do it
  1455. HDRRD1:        PUSH    CX
  1456.         MOV    CX,[SI]
  1457.         MOV    AX,[SI+2]
  1458.         MOV    AH,2        ;Set code
  1459.         INT    13H        ;Call interrupt
  1460.         POP    CX
  1461. ;        JC    HDRRDERR    ;Jump if error
  1462.         ADD    SI,4
  1463.         LOOP    HDRRD1
  1464.         XOR    AX,AX        ;All ok
  1465. ;Exit
  1466. HDRRDX:
  1467.         POP    ES
  1468.         POP    DS
  1469.         POP    SI
  1470.         POP    DX
  1471.         POP    CX
  1472.         POP    BX
  1473.         POP    BP
  1474.         RET
  1475. ; HDRRDERR:    MOV    AX,CX
  1476. ;        MOV    AL,AH         ;Error code in AX
  1477. ;        XOR    AH,AH
  1478. ;        JMP    HDRRDX
  1479. _hd_rread    ENDP
  1480.  
  1481. ;***************************
  1482. ;     hd_1seek             *
  1483. ;***************************
  1484. ; Call with:
  1485. ;       hd_1seek(drive,cyl,bufseg)
  1486. ;    drive = drive to seek on
  1487. ;    cyl = cylinder to seek to (head 0, sector 1)
  1488. ;    bufseg = seg. of buffer to hold 1 sector
  1489. ;
  1490. HD1DRIVE    =    [BP+4]
  1491. HD1CYL        =    [BP+6]
  1492. HD1SEG        =    [BP+8]
  1493.         PUBLIC    _hd_1seek
  1494. _hd_1seek    PROC    NEAR
  1495.         PUSH    BP
  1496.         MOV    BP,SP
  1497.         PUSH    BX
  1498.         PUSH    CX
  1499.         PUSH    DX
  1500.         PUSH    ES
  1501. ; Set up segments
  1502.         MOV    AX,HD1SEG
  1503.         MOV    ES,AX
  1504. ; Zero offset
  1505.         XOR    BX,BX
  1506. ;Set up drive
  1507.         MOV    DX,HD1DRIVE
  1508.         XOR    DH,DH        ;Head 0
  1509.         MOV    CX,HD1CYL    ;Cylinder
  1510.         MOV    AX,CX
  1511.         SHR    AX,1
  1512.         SHR    AX,1
  1513.         MOV    CH,CL        ;Adjust
  1514.         MOV    CL,AH
  1515.         AND    CL,0C0H
  1516.         INC    CL
  1517.         MOV    AL,1
  1518.         MOV    AH,2
  1519.         INT    13H
  1520.         JC    HD1SERR
  1521.  
  1522. HD1SEX:        POP    ES
  1523.         POP    DX
  1524.         POP    CX
  1525.         POP    BX
  1526.         POP    BP
  1527.         RET
  1528. HD1SERR:    MOV    AL,AH
  1529.         XOR    AH,AH
  1530.         JMP    HD1SEX
  1531. _hd_1seek    ENDP
  1532.  
  1533. ;**************************************
  1534. ;        EMS FUNCTIONS FOLLOW         *
  1535. ;**************************************
  1536.  
  1537. ;****************************
  1538. ;       do_ems              *
  1539. ;****************************
  1540. ; Call with:
  1541. ;    do_ems(pfseg,numpages,memseg,width)
  1542. ;    pfseg is the page frame segment address
  1543. ;    numpages is number of EMS pages to allocate per handle
  1544. ;    memseg is pointer to a 16K segment in conventional memory
  1545. ;    width is transfer width -1=byte, 0=word, 1=doubleword
  1546. ; This fellow runs the following test
  1547. ;   1. Create two handles, allocating to each numpages EMS
  1548. ;      pages
  1549. ;   2. Copy contents of memseg into first handle's EMS memory
  1550. ;   3. Copy contents of memseg into second handle's EMS memory
  1551. ;   4. Copy entire contents of second handle's EMS memory back
  1552. ;      into first.
  1553. ;   5. Deallocate pages
  1554. ;
  1555.     PUBLIC    _do_ems
  1556. PFSEG        equ    [BP+4]
  1557. NUMPAGES    equ    [BP+6]
  1558. MEMSEG        equ    [BP+8]
  1559. EMSWIDTH    equ    [BP+10]
  1560. _do_ems    PROC    NEAR
  1561. ;Save registers
  1562.     PUSH    BP
  1563.     MOV    BP,SP
  1564.     PUSH    BX
  1565.     PUSH    CX
  1566.     PUSH    DX
  1567.     PUSH    SI
  1568.     PUSH    DI
  1569.     PUSH    ES
  1570.     PUSH    DS
  1571. ;Allocate numpages for handle 1
  1572.     MOV    AH,43H
  1573.     MOV    BX,NUMPAGES
  1574.     INT    67H
  1575.     OR    AH,AH        ;Any errors?
  1576.     JZ    DOEMS1
  1577.     MOV    AL,1        ;Phase in AL
  1578.     JMP    EMSERR
  1579. DOEMS1:    MOV    HANDLE1,DX
  1580. ;Allocate numpages for handle 2
  1581.     MOV    AH,43H
  1582.     MOV    BX,NUMPAGES
  1583.     INT    67H
  1584.     OR    AH,AH        ;All ok?
  1585.     JZ    DOEMS2
  1586.     MOV    AL,2
  1587.     JMP    EMSERR
  1588. DOEMS2:    MOV    HANDLE2,DX
  1589. ;Load handle 1 up with information
  1590.     MOV    DX,HANDLE1
  1591.     CALL    LOAD_HANDLE
  1592.     OR    AX,AX
  1593.     JZ    DOEMS3
  1594.     MOV    AL,3        ;Error in phase 3
  1595.     JMP    EMSERR
  1596. ;Load handle 2 with information
  1597. DOEMS3:    MOV    DX,HANDLE2
  1598.     CALL    LOAD_HANDLE
  1599.     OR    AX,AX
  1600.     JZ    DOEMS4
  1601.     MOV    AL,4        ;Error in phase 4
  1602.     JMP    EMSERR
  1603. ;Copy handle 2's contents into handle 1
  1604. DOEMS4:    MOV    AX,PFSEG
  1605.     MOV    DS,AX        ;Set up source
  1606.     ADD    AX,1024        ;Destination is 2nd page in frame
  1607.     MOV    ES,AX
  1608. ;
  1609.     XOR    BX,BX
  1610. DOEMS5:    PUSH    BX        ;Save number of pages
  1611. ;Map handle 2's page in
  1612.     XOR    AL,AL        ;Physical page 0
  1613.     MOV    AH,44H        ;Interrupt
  1614.     INT    67H
  1615.     OR    AH,AH        ;All ok?
  1616.     JZ    DOEMS6
  1617.     MOV    AL,5        ;Error in phase 5
  1618.     JMP    EMSERR    
  1619. ;Map handle 1's page in
  1620. DOEMS6:
  1621.     MOV    AL,1        ;Physical page 1
  1622.     MOV    AH,44H        ;Interrupt
  1623.     INT    67H
  1624.     OR    AH,AH        ;All ok?
  1625.     JZ    DOEMS7
  1626.     MOV    AL,6        ;Error in phase 6
  1627.     JMP    EMSERR
  1628. ;Copy stuff
  1629. DOEMS7:
  1630.     CALL    COPYPAGE
  1631. ;See if done
  1632.     POP    BX
  1633.     INC    BX
  1634.     CMP    BX,NUMPAGES
  1635.     JL    DOEMS5
  1636. ;All done with copy - deallocate
  1637.     CALL    DEALLOC_PAGES
  1638. ;Show all ok
  1639.     XOR    AX,AX
  1640. ;Restore registers and exit
  1641. EMSXIT:
  1642.     POP    DS
  1643.     POP    ES
  1644.     POP    DI
  1645.     POP    SI
  1646.     POP    DX
  1647.     POP    CX
  1648.     POP    BX
  1649.     POP    BP
  1650.     RET
  1651. ;Error exit
  1652. EMSERR:
  1653.     XCHG    AH,AL
  1654.     PUSH    AX
  1655.     CALL    DEALLOC_PAGES
  1656.     JMP    EMSXIT
  1657. _do_ems    ENDP
  1658.  
  1659. ;****************************
  1660. ;     dealloc_pages         *
  1661. ;****************************
  1662. DEALLOC_PAGES    PROC    NEAR
  1663.     MOV    DX,HANDLE1
  1664.     MOV    AH,45H
  1665.     INT    67H
  1666.     MOV    DX,HANDLE2
  1667.     MOV    AH,45H
  1668.     INT    67H
  1669.     RET
  1670. DEALLOC_PAGES    ENDP
  1671.  
  1672. ;****************************
  1673. ;     load_handle           *
  1674. ;****************************
  1675. ; Call with:
  1676. ;   DX = handle number to load
  1677. ; Returns:
  1678. ;   AX = 0 if ok, else error
  1679. LOAD_HANDLE    PROC    NEAR
  1680. ;Load up segment registers
  1681.     MOV    AX,MEMSEG
  1682.     MOV    DS,AX        ;Memory segment
  1683.     MOV    AX,PFSEG
  1684.     MOV    ES,AX        ;Page frame segment
  1685.     XOR    BX,BX        ;Start at page 0
  1686. LOADHAN1:
  1687.     PUSH    BX
  1688.     XOR    AL,AL        ;Physical page 0
  1689.     MOV    AH,44H        ;Interrupt
  1690.     INT    67H
  1691.     OR    AH,AH        ;All ok?
  1692.     JZ    LOADHAN2
  1693.     POP    BX        ;Clear stack
  1694.     JMP    LOADHANX    ;Error exit
  1695. ;Page now in page frame, copy stuff in
  1696. LOADHAN2:
  1697.     CALL    COPYPAGE
  1698. ;Move to next frame
  1699.     POP    BX
  1700.     INC    BX
  1701.     CMP    BX,NUMPAGES
  1702.     JL    LOADHAN1
  1703.     XOR    AX,AX        ;All ok
  1704. LOADHANX:
  1705.     RET
  1706. LOAD_HANDLE    ENDP
  1707.  
  1708. ;****************************
  1709. ;       copypage            *
  1710. ;****************************
  1711. ; Copies one page.  It is the caller's responsibility to set
  1712. ; up the segment registers appropriately
  1713. COPYPAGE    PROC    NEAR
  1714. ;Set up common stuff
  1715.     MOV    AX,EMSWIDTH    ;Copy width?
  1716.     OR    AX,AX
  1717.     JS    COPYBYTE
  1718.     JZ    COPYWORD
  1719. ;Doubleword copy (386/486 only! )
  1720. .386
  1721.     MOV    CX,4096        ;Number of doublewords
  1722.     XOR    ESI,ESI
  1723.     XOR    EDI,EDI
  1724.      REP    MOVSD
  1725.     RET
  1726. .8086
  1727. ;Word-wide copy
  1728. COPYWORD:
  1729.     MOV    CX,8192
  1730.     XOR    SI,SI
  1731.     XOR    DI,DI
  1732.     REP    MOVSW
  1733.     RET
  1734. ;Byte-wide copy
  1735. COPYBYTE:
  1736.     MOV    CX,16384
  1737.     XOR    SI,SI
  1738.     XOR    DI,DI
  1739.     REP    MOVSB
  1740.     RET
  1741. COPYPAGE    ENDP
  1742.  
  1743. ;
  1744. ; void start_timer(void)
  1745. ; call as:
  1746. ;    start_timer()
  1747.     public    _start_timer
  1748. _start_timer    proc    near
  1749.  
  1750.     push    ax
  1751.     push    dx
  1752.     push    ds
  1753. ;clear the accumulators
  1754.     mov    timer_micro,0
  1755.     mov    timer_milli,0
  1756.     mov    timer_sec,0
  1757. ;initialize counter 0 of 8253 timer
  1758.     mov    al,00110100b        ;ctr 0, lsb then msb,
  1759.                     ;...mode 2, binary
  1760.     out    TIMER_MODE,al        ;mode register for 8253
  1761.     sub    ax,ax            ;0 results in max count
  1762.     out     TIMER0,al        ; lsb
  1763.     out    TIMER0,al        ; msb
  1764.  
  1765. ;read current bios time-of-day
  1766.     mov    dx,BIOS_DATASEG
  1767.     mov    ds,dx
  1768.     mov    ax, ds:[BIOS_TIME_LO]
  1769.     pop    ds            ;restore my ds
  1770.     mov    count_low,ax
  1771.     pop    dx
  1772.     pop    ax
  1773.     ret
  1774. _start_timer    endp
  1775.  
  1776. ;
  1777. ; void stop_timer (unsigned int *)
  1778. ; call:
  1779. ;   stop_timer(tarray)
  1780. ; where:
  1781. ;   tarray is defined as    unsigned int tarray[3]
  1782. ;   tarray[0]=elapsed time, microseconds
  1783. ;   tarray[1]=elapsed time, milliseconds
  1784. ;   tarray[2]=elapsed time, seconds
  1785. ;
  1786.  
  1787.     public    _stop_timer
  1788. _stop_timer     proc     near
  1789.     push    bp
  1790.     mov    bp,sp
  1791.     push    ax
  1792.     push    bx
  1793.     push    cx
  1794.     push    dx
  1795.     push    di
  1796.     push    si
  1797. ;read counter 0 of 8253 timer
  1798.     xor    al,al        ;latch counter for read
  1799.     cli            ;interrupts off
  1800.     out    TIMER_MODE,al
  1801.     in    al,TIMER0
  1802.     mov    dl,al
  1803.     in    al,TIMER0
  1804.     mov    dh,al        ;dx has 16-bit timer count
  1805.  
  1806. ; we'll defer calculations till after sti
  1807.     mov    svd_8253_count, dx
  1808.  
  1809. ;get bios time
  1810.     push    ds        ;save my data seg
  1811.     mov    dx,BIOS_DATASEG
  1812.     mov    ds,dx
  1813.     mov    ax,ds:[BIOS_TIME_LO]
  1814.     pop    ds
  1815.     sti            ;ints ok now
  1816.     sub    ax,count_low
  1817.     mul    count_convert
  1818.     cmp    dx, 1000
  1819.     jb    no_overflow
  1820.  
  1821. ; dx is too large, need to pre-divide by 1000
  1822.  
  1823.     push    cx    ; use cx as swapping reg
  1824.     push    ax    ; save current low word microsecs
  1825.     mov    ax, dx    ; move hi word microsecs to dividend
  1826.     xor    dx, dx    
  1827.     div    thousand    ; now ax = hi word millis, dx = hi w micros
  1828.     mov    cx, ax        ; save hi word millis
  1829.     pop    ax        ; pop low word microsecs to dividend lo
  1830.     div    thousand
  1831.     mov    count_micro, dx ; save microseconds
  1832.     mov    dx, cx        ; now dx=count_milli_hi, ax=count_milli_lo
  1833.     div    thousand    ; now ax=count secs, dx=count_milli
  1834.     mov    count_milli, dx
  1835.     mov    timer_sec, ax
  1836.     pop    cx
  1837. jmp    short    gotcount
  1838.  
  1839. no_overflow:
  1840.     div    thousand
  1841.     mov    count_milli,ax    ;save milliseconds
  1842.     mov    count_micro,dx    ;save microseconds
  1843. gotcount:
  1844.  
  1845. ;calc time from 8253
  1846.     mov    dx, svd_8253_count
  1847.     or    ax, MAX_COUNT
  1848.     sub    ax,dx        ;timer count value
  1849.     mul    timer_convert    ;<10000, so overflow not possible
  1850.     div    ten_thousand    ;give time in usec
  1851.     mov    timer_micro,ax    ;save usec, round nsec
  1852.     cmp    dx,five_thousand
  1853.     jb    cont
  1854.     inc    timer_micro    ;round up
  1855. cont:
  1856.  
  1857. ;restore bios numbers
  1858.  
  1859.     mov    ax, count_milli
  1860.     mov    dx, count_micro
  1861.  
  1862. ;check for jitter
  1863.  
  1864.     cmp    timer_sec, 0
  1865.     jne    jitter_ok
  1866.     cmp    ax,0
  1867.     jne    jitter_ok
  1868.     mov    ax,_timeradjust
  1869.     cmp    timer_micro,ax
  1870.     jae    jitter_ok
  1871.     mov    timer_micro,ax
  1872.  
  1873. ;put results in timer variables
  1874. jitter_ok:
  1875.     mov    ax,dx        ;get count_micro
  1876.     add    ax,timer_micro    ;sum micro fields
  1877.     cmp    ax,_timeradjust    ;check for underflow
  1878.     jae    compensate
  1879.     dec    count_milli    ;borrow
  1880.     add    ax,1000
  1881. compensate:
  1882.     sub    ax,_timeradjust    ;compensate for timer delays
  1883.     mov    timer_micro,ax
  1884.     cmp    ax,1000        ;check field overflow
  1885.     jb    fld_ok        ;timer micro field ok
  1886.     sub    dx,dx        ;too large
  1887.     div    thousand    ;so carry out into timer_milli
  1888.     mov    timer_milli,ax
  1889.     mov    timer_micro,dx
  1890. fld_ok:
  1891.     mov    ax,count_milli    ;sum milli field
  1892.     add    timer_milli,ax
  1893.     cmp    timer_milli,1000    ;check as above
  1894.     jb    goback
  1895.     sub    dx,dx
  1896.     mov    ax,timer_milli
  1897.     div    thousand
  1898.     add    timer_sec,ax
  1899.     mov    timer_milli,dx
  1900. ;send it all back
  1901. goback:
  1902.     push    ds
  1903.     pop    es
  1904.     mov    di, [bp+4]        ;pointer to array
  1905.     mov    si, offset timer_micro
  1906.     movsw
  1907.     movsw
  1908.     movsw
  1909.     pop    si
  1910.     pop    di
  1911.     pop    dx
  1912.     pop    cx
  1913.     pop    bx
  1914.     pop    ax
  1915.     pop    bp
  1916.     ret
  1917. _stop_timer    endp
  1918.  
  1919.  
  1920. ;****************************
  1921. ;           setp            *
  1922. ;****************************
  1923. ; Set pixel at x,y to color. Mode is mode #.
  1924. ; Call with:
  1925. ;   AX = y coordinate of pixel to set
  1926. ;   BX = x coordinate of pixel to set
  1927. ;   CX = mode
  1928. ;   DX = color
  1929. ; NOTE:
  1930. ;  This routine assumes that ES points to the current video
  1931. ;  page.  It is the caller's job to do this.
  1932. SETPIXEL    PROC    NEAR
  1933.         PUSH    AX
  1934.         PUSH    BX
  1935.         PUSH    CX
  1936.         PUSH    DX
  1937. ;Determine which routine to execute using mode
  1938. ;First check for Hercules
  1939.         CMP    CL,255
  1940.         JNE    SETPIXEL10
  1941. ;
  1942. ; Hercules mode
  1943.         CALL CALCPH
  1944. SETPIXEL01:
  1945.         SHL    DX,CL        ;Shift color
  1946.         NOT    DH
  1947.         AND    ES:[BX],DH    ;Zero the pixel
  1948.         OR    ES:[BX],DL    ;Set it
  1949. SETPIXEXIT:
  1950.         POP    DX
  1951.         POP    CX
  1952.         POP    BX
  1953.         POP    AX
  1954.         RET
  1955. ;
  1956. SETPIXEL10:
  1957.         CMP    CL,6
  1958.         JGE    SETPIXEL20
  1959. ;
  1960. ;Modes 4 and 5
  1961. ;
  1962.         CALL     CALCP4
  1963.         JMP    SHORT SETPIXEL01    ;Borrow code
  1964. ;
  1965. SETPIXEL20:
  1966.         CMP    CL,13
  1967.         JGE    SETPIXEL30
  1968. ;
  1969. ;Mode 6
  1970. ;
  1971.         CALL     CALCP6
  1972.         JMP    SHORT SETPIXEL01    ;Borrow code
  1973. ;
  1974. SETPIXEL30:
  1975.         CMP    CL,14
  1976.         JGE    SETPIXEL40
  1977. ;
  1978. ;Mode 13
  1979. ;
  1980.         CALL     CALCP13
  1981. SETPIXEL31:
  1982.         SHL    DH,CL        ;Position mask
  1983.         MOV    CX,DX        ;Move mask/color to safety
  1984.         MOV    AH,DH
  1985.         MOV    DX,3CEH        ;Address register port
  1986.         MOV    AL,8        ;Mask register number
  1987.         OUT    DX,AX
  1988.         MOV    AX,205H        ;Mode register number 2, write mode 2
  1989.         OUT    DX,AX
  1990.         MOV    AH,0        ;Replace mode
  1991.         MOV    AL,3        ;Data rotate/function select register
  1992.         OUT    DX,AX
  1993.         MOV    AL,ES:[BX]    ;Load the latches
  1994.         MOV    ES:[BX],CL    ;Store it
  1995.         MOV    AX,0FF08H    ;Restore defaults
  1996.         OUT    DX,AX
  1997.         MOV    AX,5
  1998.         OUT    DX,AX
  1999.         MOV    AX,3
  2000.         OUT    DX,AX
  2001.         JMP    SETPIXEXIT
  2002. ;
  2003. SETPIXEL40:
  2004.         CMP    CL,17
  2005.         JGE    SETPIXEL50
  2006. ;
  2007. ; Modes 14,15,16
  2008. ;
  2009. SETPIXEL41:
  2010.         CALL    CALCP14
  2011.         JMP    SHORT SETPIXEL31    ;Borrow code
  2012. ;
  2013. SETPIXEL50:
  2014.         CMP    CL,18
  2015.         JGE    SETPIXEL60
  2016. ;
  2017. ; Mode 17
  2018. ;
  2019.         CALL    CALCP14
  2020.         JMP    SHORT SETPIXEL01    ;Borrow code
  2021. ;
  2022. SETPIXEL60:
  2023.         CMP    CL,18
  2024.         JZ    SETPIXEL41            ;18 same as EGA
  2025. ;
  2026. ; Mode 19
  2027. ;
  2028.         CALL     CALCP19
  2029.         MOV    ES:[BX],DL    ;set it
  2030.         JMP    SETPIXEXIT
  2031. SETPIXEL        ENDP
  2032.  
  2033. ;****************************
  2034. ;        getp               *
  2035. ;****************************
  2036. ; Get a pixel's contents.
  2037. ; Call with:
  2038. ;  AX = y coordinate
  2039. ;  BX = x coordinate
  2040. ;  CX = mode
  2041. ; Returns:
  2042. ;  DL = color
  2043. ;
  2044. GETP        PROC    NEAR
  2045.         PUSH    AX
  2046.         PUSH    BX
  2047.         PUSH    CX
  2048.         CMP    CL,255        ;Hercules mode selected by 255
  2049.         JNE    GETP10
  2050. ;
  2051. ; Hercules monochrome mode
  2052. ;
  2053.         CALL    CALCPH
  2054. GETP01:
  2055.         MOV    DL,ES:[BX]
  2056.         SHR     DL,CL
  2057.         AND     DL,DH
  2058. GETPEXIT:    POP    CX
  2059.         POP    BX
  2060.         POP    AX
  2061.         RET
  2062. ;
  2063. GETP10:
  2064.         CMP    CL,6
  2065.         JGE    GETP20
  2066. ;
  2067. ; Modes 4 and 5
  2068. ;
  2069.         CALL    CALCP4
  2070.         JMP    SHORT GETP01    ;Borrow code
  2071. ;
  2072. GETP20:
  2073.         CMP    CL,7
  2074.         JGE    GETP30
  2075. ;
  2076. ; Mode 6
  2077. ;
  2078.         CALL    CALCP6
  2079.         JMP    SHORT GETP01    ;Borrow code
  2080. ;
  2081. GETP30:
  2082.         CMP    CL,14
  2083.         JGE    GETP40
  2084. ;
  2085. ; Mode 13
  2086. ;
  2087.         CALL    CALCP13
  2088. GETP31:
  2089.         MOV    CH,DH
  2090.         SHL    CH,CL
  2091.         MOV    SI,BX
  2092.         MOV    DX,3CEH
  2093.         MOV    AX,304H
  2094.         XOR    BL,BL
  2095. GETP32:
  2096.         OUT    DX,AX
  2097.         MOV    BH,ES:[SI]
  2098.         AND    BH,CH
  2099.         NEG    BH
  2100.         ROL    BX,1
  2101.         DEC    AH
  2102.         JGE    GETP32
  2103.         MOV    DL,BL
  2104.         JMP    GETPEXIT
  2105. ;
  2106. GETP40:
  2107.         CMP    CL,15
  2108.         JL      GETP51
  2109.         JNE    GETP50
  2110. ;
  2111. ; Special for mode 15
  2112. ;
  2113.         CALL    CALCP14
  2114.         MOV    CH,DH
  2115.         SHL    CH,CL
  2116.         MOV    SI,BX
  2117.         MOV    DX,3CEH
  2118.         MOV    AX,204H
  2119.         XOR    BL,BL
  2120. GETP41:
  2121.         OUT    DX,AX
  2122.         MOV    BH,ES:[SI]
  2123.         AND    BH,CH
  2124.         NEG    BH
  2125.         ROL    BX,1
  2126.         SUB    AH,2
  2127.         JGE    GETP41
  2128.         MOV    DL,BL
  2129.         JMP    GETPEXIT
  2130. ; Mode 17
  2131. GETP50:
  2132.         CMP    CL,17
  2133.         JNZ    GETP60
  2134.         CALL    CALCP14
  2135.         MOV    DL,ES:[BX]
  2136.         SHR    DL,CL
  2137.         AND    DL,DH
  2138.         JMP    GETPEXIT
  2139. ;
  2140. ; Modes 14 and 16
  2141. ;
  2142. GETP51:
  2143.         CALL    CALCP14
  2144.         JMP    GETP31        ;Borrow code
  2145. ;
  2146. GETP60:
  2147.         CMP    CL,18
  2148.         JLE    GETP51        ;Mode 18 same as EGA 14 and 16
  2149. ;
  2150. ; Mode 19
  2151. ;
  2152.         CALL    CALCP19
  2153.         MOV    DL,ES:[BX]
  2154.         JMP    GETPEXIT
  2155. GETP        ENDP
  2156.  
  2157. ;****************************
  2158. ; ROUTINES FOR CALCULATING A
  2159. ; PIXEL'S ADDRESS FOLLOW.
  2160. ;
  2161. ; Calculate pixel address for modes 4 and 5
  2162. ; Entry: AX = y coord
  2163. ;        BX = x coord
  2164. ; Exit:  DH = bit mask
  2165. ;        BX = byte offset
  2166. ;        CL = number of bits to shift
  2167. CALCP4        PROC    NEAR
  2168.         MOV    CL,BL
  2169.         XCHG    AH,AL
  2170.         SHR    AX,1
  2171.         ADD    BH,AL
  2172.         XOR    AL,AL
  2173.         ADD    BX,AX
  2174.         SHR    AX,1
  2175.         SHR    AX,1
  2176.         ADD    BX,AX
  2177.         SHR    BX,1
  2178.         SHR    BX,1
  2179.         MOV    DH,3
  2180.         AND    CL,DH
  2181.         XOR    CL,DH
  2182.         SHL    CL,1
  2183.         RET
  2184. CALCP4        ENDP
  2185. ;
  2186. ; Calculate address of pixel for mode 6
  2187. ; Entry: See abov
  2188. ; Exit: See above
  2189. ;
  2190. CALCP6        PROC    NEAR
  2191.         MOV    CL,BL
  2192.         XCHG    AH,AL
  2193.         SHR    BX,1
  2194.         SHR    AX,1
  2195.         ADD    BH,AL
  2196.         XOR    AL,AL
  2197.         ADD    BX,AX
  2198.         SHR    AX,1
  2199.         SHR    AX,1
  2200.         ADD    BX,AX
  2201.         SHR    BX,1
  2202.         SHR    BX,1
  2203.         AND    CL,7
  2204.         XOR    CL,7
  2205.         MOV    DH,1
  2206.         RET
  2207. CALCP6        ENDP
  2208. ;
  2209. ; Calculate pixel address for mode 13
  2210. ; Entry: See above
  2211. ; Exit: See above
  2212. ;
  2213. CALCP13:
  2214.         MOV    CL,BL
  2215.         MOV    CH,DL        ;Save color and borrow...
  2216.         MOV    DX,40        ;...DX
  2217. CP13COM:
  2218.         MUL    DX
  2219.         SHR    BX,1
  2220.         SHR    BX,1
  2221.         SHR    BX,1
  2222.         ADD    BX,AX
  2223.         AND    CL,7
  2224.         XOR    CL,7
  2225.         MOV    DL,CH        ;Restore color
  2226.         MOV     DH,1
  2227.         RET
  2228. ;
  2229. ; Calculate pixel address for modes 14,15,16,17,18
  2230. ; Entry: See above
  2231. ; Exit: See above
  2232. ;
  2233. CALCP14:
  2234.         MOV    CL,BL
  2235.         MOV    CH,DL        ;Save color
  2236.         MOV    DX,80
  2237.         JMP    SHORT CP13COM
  2238. ;
  2239. ; Calculate pixel address for mode 19
  2240. ; Entry: See above
  2241. ; Exit: See above
  2242. ; Note: we don't need a bit mask in AH or a shift count in CL 
  2243. ;       for this mode.
  2244. ;
  2245. CALCP19        PROC    NEAR
  2246.         XCHG    AH,AL
  2247.         ADD    BX,AX
  2248.         SHR    AX,1
  2249.         SHR    AX,1
  2250.         ADD    BX,AX
  2251.         RET
  2252. CALCP19        ENDP
  2253. ;
  2254. ; Calculate pixel address for Hercules graphics mode
  2255. ;
  2256. CALCPH        PROC    NEAR
  2257.         MOV    CL,BL
  2258.         SHR     AX,1
  2259.         RCR     BX,1
  2260.         SHR     AX,1
  2261.         RCR     BX,1
  2262.         SHR     BX,1
  2263.         MOV     AH,90
  2264.         MUL     AH
  2265.         ADD     BX,AX
  2266.         AND     CL,7
  2267.         XOR     CL,7
  2268.         MOV     DH,1
  2269.         RET
  2270. CALCPH        ENDP
  2271. ;****************************
  2272. ;         svmode            *
  2273. ;****************************
  2274. ; Set video mode.  Call with:
  2275. ;* svmode(mode) int mode; 
  2276. ;  Set video mode.
  2277. ;  Mode is:
  2278. ;  0 - 40 x 25 chars b&w (cga,ega,mcga,vga)
  2279. ;  1 - 40 x 25 chars color (cga,ega,mcga,vga)
  2280. ;  2 - 80 x 25 chars b&w (cga,ega,mcga,vga)
  2281. ;  3 - 80 x 25 chars color (cga,ega,mcga,vga)
  2282. ;  4 - 320 x 200 4-color graph (cga,ega,mcga,vga)
  2283. ;  5 - 320 x 200 b&w graph (cga,ega,mcga,vga)
  2284. ;  6 - 640 x 200 b&w graph (cga,ega,mcga,vga)
  2285. ;  7 - 80 x 25 chars b&w (mda,ega,vga)
  2286. ;  8 - 160 x 200 16-color graph (jr)
  2287. ;  9 - 320 x 200 16-color graph (jr)
  2288. ;  10 - 640 x 200 4-color graph (jr)
  2289. ;  11 - reserved by EGA video BIOS
  2290. ;  12 - reserved by EGA video BIOS
  2291. ;  13 - 320 x 200 16-color graph (ega,vga)
  2292. ;  14 - 640 x 200 16-color graph (ega,vga)
  2293. ;  15 - 640 x 350 2-color graph (ega,vga)
  2294. ;  16 - 640 x 350 4- or 16-color (ega,vga)
  2295. ;  17 - 640 x 480 2-color (mcga,vga)
  2296. ;  18 - 640 x 480 16-color (vga)
  2297. ;  19 - 320 x 200 256-color (mcga,vga)
  2298. ;  255 - Heculese 720x348 monochrome graphics
  2299.     PUBLIC    _svmode
  2300. _svmode    PROC    NEAR
  2301.     PUSH    BP
  2302.     MOV    BP,SP
  2303.     PUSH    SI
  2304.     PUSH    DI
  2305.     MOV    AX,4[BP]
  2306.     CMP    AX,255        ;Hercules?
  2307.     JZ    HERC
  2308.     PUSH    DS
  2309.     MOV    BX,40H        ;Video display data area
  2310.     MOV    DS,BX
  2311.     MOV    BL,32        ;Presence of CGA
  2312.     MOV    AX,4[BP]
  2313.     MOV    DL,AL
  2314.     AND    DL,7
  2315.     CMP    DL,7
  2316.     JNE    SVM1
  2317.     MOV    BL,48        ;Presence of MDA
  2318. SVM1:    AND    BYTE PTR DS:[10H],11001111B
  2319.     OR    BYTE PTR DS:[10H],BL
  2320.     INT    10H    ;Set the mode
  2321.     POP    DS        ;Restore DS
  2322.     POP    DI
  2323.     POP    SI
  2324.     POP    BP
  2325.     RET
  2326. HERC:
  2327. ;Update video bios data area
  2328.     PUSH    ES
  2329.     MOV    AX,40H
  2330.     MOV    ES,AX
  2331.     MOV    DI,49H    ;ES:DI is video bios data area
  2332.     MOV    SI,OFFSET BDATA
  2333.     MOV    CX,BDLEN
  2334.     REP    MOVSB        ;Update video bios data
  2335. ;Set config. switch
  2336.     MOV    DX,3BFH        ;Config switch port
  2337.     MOV    AL,1        ;Exclude second 32K of video buffer
  2338.     OUT    DX,AL
  2339. ;Blank the screen
  2340.     MOV    DX,3B8H
  2341.     XOR    AL,AL
  2342.     OUT    DX,AL
  2343. ;Program the CRTC
  2344.     SUB    DL,4        ;3b4H is addres reg port of CRTC
  2345.     MOV    SI,OFFSET CRTCP
  2346.     MOV    CX,9        ;9 parameters to load
  2347. HERC1:    LODSW            ;Al=crtc register number/AH=VALUE
  2348.     OUT    DX,AX
  2349.     LOOP    HERC1
  2350. ;Set graphics mode
  2351.     ADD    DL,4
  2352.     MOV    AL,CRTMD
  2353.     OUT     DX,AL
  2354. ;Clear the video buffer
  2355.     MOV    AX,0B000H
  2356.     MOV    ES,AX
  2357.     XOR    AX,AX        ;Clear to zero
  2358.     XOR    DI,DI
  2359.     MOV    CX,4000H
  2360.     REP    STOSW
  2361.     POP    ES
  2362.     POP    DI
  2363.     POP    SI
  2364.     POP    BP
  2365.     RET            ;Go home
  2366. _svmode    ENDP
  2367.  
  2368. ;****************************
  2369. ;        gvmode             *
  2370. ;****************************
  2371. ; Get video mode.  Returns current video mode number.
  2372.     PUBLIC    _gvmode
  2373. _gvmode    PROC    NEAR
  2374.     MOV    AH,0FH
  2375.     INT    10H
  2376.     XOR    AH,AH        ;Clear hi part of mode number
  2377.     RET
  2378. _gvmode    ENDP
  2379.  
  2380.  
  2381. ;*****************************
  2382. ;     FILE IO ROUTINES       *
  2383. ;*****************************
  2384. ;
  2385. ;*****************************
  2386. ;        ll_open             *
  2387. ;*****************************
  2388. ; Open a file with read/write access.
  2389. ; Call with:
  2390. ;  hand=ll_open(nameptr)
  2391. ; Where:
  2392. ;  nameptr = pointer to file's name (null-terminated)
  2393. ; Returns handle.  If handle<0, indicates error.
  2394.         PUBLIC    _ll_open
  2395. OPENNAMEPTR    equ    [BP+4]
  2396. _ll_open    PROC    NEAR
  2397.         PUSH    BP
  2398.         MOV    BP,SP
  2399.         PUSH    DX
  2400. ;Issue the call
  2401.         MOV    DX,OPENNAMEPTR
  2402.         MOV    AH,3DH
  2403.         MOV    AL,2    ;Read/write
  2404.         INT    21H
  2405.         JC    LLOPZ
  2406. ;Return handle
  2407. LLOPX:
  2408.         POP    DX
  2409.         POP    BP
  2410.         RET
  2411. LLOPZ:        NEG    AX
  2412.         JMP    LLOPX
  2413. _ll_open    ENDP
  2414. ;*****************************
  2415. ;        ll_close            *
  2416. ;*****************************
  2417. ; Close a file.
  2418. ; Call with:
  2419. ;  ll_close(handle)
  2420. ; Where:
  2421. ;  handle = file's handle.
  2422.         PUBLIC    _ll_close
  2423. CLOSEHAND    equ    [BP+4]
  2424. _ll_close    PROC    NEAR
  2425.         PUSH    BP
  2426.         MOV    BP,SP
  2427. ;Get the handle
  2428.         MOV    BX,CLOSEHAND
  2429.         MOV    AH,3EH
  2430.         INT    21H
  2431.         POP    BP
  2432.         RET
  2433. _ll_close    ENDP
  2434.  
  2435. ;*****************************
  2436. ;        ll_create           *
  2437. ;*****************************
  2438. ; Create a file with read/write access.
  2439. ; Call with:
  2440. ;  hand=ll_create(nameptr)
  2441. ; Where:
  2442. ;  nameptr = pointer to file's name (null-terminated)
  2443. ; Returns handle.  If handle<0, indicates error.
  2444.         PUBLIC    _ll_create
  2445. CREATNAMEPTR    equ    [BP+4]
  2446. _ll_create    PROC    NEAR
  2447.         PUSH    BP
  2448.         MOV    BP,SP
  2449. ;Get the file name and create it.
  2450.         MOV    DX,CREATNAMEPTR
  2451.         MOV    AH,3CH
  2452.         XOR    CX,CX
  2453.         INT    21H
  2454.         JC    LLCRZ
  2455. ;Return handle
  2456. LLCRX:        POP    BP
  2457.         RET
  2458. ;Return error
  2459. LLCRZ:        NEG    AX
  2460.         JMP    LLCRX
  2461. _ll_create    ENDP
  2462.  
  2463. ;*****************************
  2464. ;      ll_seekread           *
  2465. ;*****************************
  2466. ; Seek-and-read an open file.
  2467. ; Call with:
  2468. ;  result=ll_seekread(handle,offset,mode,buffer,nbytes)
  2469. ; Where:
  2470. ;  handle = handle of file to read
  2471. ;  offset = byte offset
  2472. ;  mode = offset mode
  2473. ;  buffer = segment of buffer to read into
  2474. ;  nbytes = number of bytes to read
  2475. ; Returns:
  2476. ;  Number of bytes actually read.  If error, result is negative
  2477. ;  and contains error code.
  2478. ; Note: The data is read into the segment starting at offset 0.
  2479.         PUBLIC    _ll_seekread
  2480. SRHANDLE    equ    [BP+4]
  2481. SROFFSETL    equ    [BP+6]
  2482. SROFFSETH    equ    [BP+8]
  2483. SRMODE        equ    [BP+10]
  2484. SRBUFFSEG    equ    [BP+12]
  2485. SRNBYTES    equ    [BP+14]
  2486. _ll_seekread    PROC    NEAR
  2487.         PUSH    BP
  2488.         MOV    BP,SP
  2489.         PUSH    BX
  2490.         PUSH    CX
  2491.         PUSH    DX
  2492.         PUSH    DS
  2493. ;Do the seek first
  2494.         MOV    BX,SRHANDLE    ;Get handle
  2495.         MOV    DX,SROFFSETL    ;Get byte offset
  2496.         MOV    CX,SROFFSETH
  2497.         MOV    AX,SRMODE
  2498.         MOV    AH,42H
  2499.         INT    21H        ;Do the seek
  2500.         JC    SRERR        ;Error if carry set
  2501. ;Now do the read
  2502.         MOV    AX,SRBUFFSEG
  2503.         MOV    DS,AX
  2504.         XOR    DX,DX        ;Set address
  2505.         MOV    CX,SRNBYTES    ;Number of bytes
  2506.         MOV    AH,3FH
  2507.         INT    21H        ;Do the read
  2508.         JC    SRERR
  2509. ;Return bytes actually read
  2510. SRX:
  2511.         POP    DS
  2512.         POP    DX
  2513.         POP    CX
  2514.         POP    BX
  2515.         POP    BP
  2516.         RET
  2517. ;Return error code
  2518. SRERR:        NEG    AX
  2519.         JMP    SRX
  2520. _ll_seekread    ENDP
  2521. ;*****************************
  2522. ;      ll_seekwrite          *
  2523. ;*****************************
  2524. ; Seek-and-write an open file.
  2525. ; Call with:
  2526. ;  result=ll_seekwrite(handle,offset,mode,buffer,nbytes)
  2527. ; Where:
  2528. ;  handle = handle of file to write
  2529. ;  offset = byte offset
  2530. ;  mode = seek mode
  2531. ;  buffer = segment of buffer to write from
  2532. ;  nbytes = number of bytes to write
  2533. ; Returns:
  2534. ;  Number of bytes actually written.  If error, result is negative
  2535. ;  and contains error code.
  2536. ; Note: The data is written from the segment starting at offset 0.
  2537.         PUBLIC    _ll_seekwrite
  2538. SWHANDLE    equ    [BP+4]
  2539. SWOFFSETL    equ    [BP+6]
  2540. SWOFFSETH    equ    [BP+8]
  2541. SWMODE        equ    [BP+10]
  2542. SWBUFFSEG    equ    [BP+12]
  2543. SWNBYTES    equ    [BP+14]
  2544. _ll_seekwrite    PROC    NEAR
  2545.         PUSH    BP
  2546.         MOV    BP,SP
  2547.         PUSH    BX
  2548.         PUSH    CX
  2549.         PUSH    DX
  2550.         PUSH    DS
  2551. ;Do the seek first
  2552.         MOV    BX,SWHANDLE    ;Get handle
  2553.         MOV    DX,SWOFFSETL    ;Get byte offset
  2554.         MOV    CX,SWOFFSETH
  2555.         MOV    AX,SWMODE    ;Seek mode
  2556.         MOV    AH,42H
  2557.         INT    21H        ;Do the seek
  2558.         JC    SWERR        ;Error if carry set
  2559. ;Now do the write
  2560.         MOV    AX,SWBUFFSEG
  2561.         MOV    DS,AX
  2562.         XOR    DX,DX        ;Set address
  2563.         MOV    CX,SWNBYTES    ;Number of bytes
  2564.         MOV    AH,40H
  2565.         INT    21H        ;Do the write
  2566.         JC    SWERR
  2567. ;Return bytes actually write
  2568. SWX:
  2569.         POP    DS
  2570.         POP    DX
  2571.         POP    CX
  2572.         POP    BX
  2573.         POP    BP
  2574.         RET
  2575. ;Return error code
  2576. SWERR:        NEG    AX
  2577.         JMP    SWX
  2578. _ll_seekwrite    ENDP
  2579. ;****************************
  2580. ;          ll_filelen       *
  2581. ;****************************
  2582. ; Return a file's length.
  2583. ;   ulong = ll_filelen(fh)
  2584.         PUBLIC    _ll_filelen
  2585. FLENFH        equ    [BP+4]        ;File handle
  2586. _ll_filelen    PROC    NEAR
  2587.         PUSH    BP
  2588.         MOV    BP,SP
  2589.         PUSH    BX
  2590.         PUSH    CX
  2591.         PUSH    DX
  2592. ;First do a seek on the file
  2593.         MOV    BX,FLENFH    ;Get handle
  2594.         XOR    CX,CX
  2595.         XOR    DX,DX        ;Offset 0
  2596.         MOV    AL,2        ;End of file
  2597.         MOV    AH,42H
  2598.         INT    21H
  2599. ;Return the offset
  2600.         POP    DX
  2601.         POP    CX
  2602.         POP    BX
  2603.         POP    BP
  2604.         RET
  2605. _ll_filelen    ENDP
  2606.         END